package com.getpebble.android.framework.appmessage;

import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable.Creator;
import com.getpebble.android.common.core.trace.Trace;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import org.json.JSONException;

public class AppMessage implements Parcelable {
    public static final Creator<AppMessage> CREATOR = new Creator<AppMessage>() {
        public AppMessage createFromParcel(Parcel source) {
            return new AppMessage(source);
        }

        public AppMessage[] newArray(int size) {
            return new AppMessage[size];
        }
    };
    private static AtomicInteger appMessageSequenceId = new AtomicInteger(0);
    protected AppMessageCommand mCommand;
    protected PebbleDictionary mPebbleDictionary;
    protected byte mTransactionId;
    protected UUID mUuid;

    public enum AppMessageCommand {
        PUSH((byte) 1),
        REQUEST((byte) 2),
        ACK((byte) -1),
        NACK(Byte.MAX_VALUE);
        
        byte mCode;

        private AppMessageCommand(byte code) {
            this.mCode = code;
        }

        public byte getCode() {
            return this.mCode;
        }

        public static AppMessageCommand fromByte(byte b) {
            for (AppMessageCommand command : values()) {
                if (command.getCode() == b) {
                    return command;
                }
            }
            return null;
        }
    }

    public AppMessage(byte transactionId, UUID uuid, AppMessageCommand command, PebbleDictionary pebbleDictionary) {
        this.mUuid = uuid;
        this.mPebbleDictionary = pebbleDictionary;
        this.mTransactionId = transactionId;
        this.mCommand = command;
    }

    public AppMessage(AppMessage other) {
        this.mUuid = other.mUuid;
        this.mTransactionId = other.mTransactionId;
        this.mCommand = other.mCommand;
        this.mPebbleDictionary = other.mPebbleDictionary;
    }

    public static byte getNextTransactionId() {
        appMessageSequenceId.compareAndSet(256, 0);
        return (byte) (appMessageSequenceId.getAndIncrement() & 255);
    }

    public UUID getUuid() {
        return this.mUuid;
    }

    public PebbleDictionary getPebbleDictionary() {
        return this.mPebbleDictionary;
    }

    public byte getTransactionId() {
        return this.mTransactionId;
    }

    public AppMessageCommand getCommand() {
        return this.mCommand;
    }

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel dest, int flags) {
        dest.writeSerializable(this.mUuid);
        dest.writeString(this.mPebbleDictionary.toJsonString());
        dest.writeByte(this.mTransactionId);
        dest.writeInt(this.mCommand == null ? -1 : this.mCommand.ordinal());
    }

    private AppMessage(Parcel in) {
        this.mUuid = (UUID) in.readSerializable();
        try {
            this.mPebbleDictionary = JsonPebbleDictionary.fromJson(in.readString());
        } catch (JSONException e) {
            Trace.error("AppMessage", "unable to parse dictionary", e);
        }
        this.mTransactionId = in.readByte();
        int tmpMCommand = in.readInt();
        this.mCommand = tmpMCommand == -1 ? null : AppMessageCommand.values()[tmpMCommand];
    }

    public String toString() {
        return "txid: " + getTransactionId() + " cmd: " + getCommand().toString();
    }
}
